﻿#region Copyright (c) 2000-2013 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2013 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2013 Developer Express Inc.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
namespace UColor.WPF.Helpers {
	public class FilterableCollection<TItem> : ICollection<TItem>, INotifyCollectionChanged, IList<TItem>, IList, ICollection, IEnumerable, IEnumerable<TItem> {
		public delegate bool FilterDelegate(TItem element);
		public event NotifyCollectionChangedEventHandler CollectionChanged;
		List<TItem> fullCollection;
		Dictionary<TItem, bool> filteredCollection;
		FilterDelegate lastUsedFilter = null;
		public FilterableCollection() : this(null) { }
		public FilterableCollection(TItem[] items) {
			fullCollection = items == null ? new List<TItem>() : new List<TItem>(items);
			filteredCollection = new Dictionary<TItem, bool>();
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}
		public void ApplyFilter(FilterDelegate filterDelegate) {
			foreach(TItem element in fullCollection) {
				if(!filterDelegate(element)) {
					if(!filteredCollection.ContainsKey(element)) {
						filteredCollection.Add(element, false);
						int index = fullCollection.IndexOf(element);
						OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, element, index - FilteredItemsBeforeIndex(index)));
					}
				} else if(filteredCollection.ContainsKey(element)) {
					filteredCollection.Remove(element);
					int index = fullCollection.IndexOf(element);
					OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, element, index - FilteredItemsBeforeIndex(index)));
				}
			}
			lastUsedFilter = filterDelegate;
		}
		public void CancelFilter() {
			lastUsedFilter = null;
			filteredCollection.Clear();
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}
		public void Add(TItem item) {
			fullCollection.Add(item);
			if(lastUsedFilter != null && !lastUsedFilter(item))
				filteredCollection.Add(item, false);
			int index = fullCollection.IndexOf(item);
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index - FilteredItemsBeforeIndex(index)));
		}
		public bool Contains(TItem item) {
			return fullCollection.Contains(item) && !filteredCollection.ContainsKey(item);
		}
		public void Clear() {
			fullCollection.Clear();
			filteredCollection.Clear();
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
		}
		public void CopyTo(TItem[] array, int arrayIndex) {
			(from item in fullCollection where !filteredCollection.ContainsKey(item) select item).ToList().CopyTo(array, arrayIndex);
		}
		public bool Remove(TItem item) {
			int index = fullCollection.IndexOf(item);
			int oldIndex = index - FilteredItemsBeforeIndex(index);
			filteredCollection.Remove(item);
			bool result = fullCollection.Remove(item);
			OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item, oldIndex));
			return result;
		}
		public virtual IEnumerator<TItem> GetEnumerator() {
			foreach(TItem item in fullCollection) {
				if(filteredCollection.ContainsKey(item))
					continue;
				yield return item;
			}
		}
		IEnumerator IEnumerable.GetEnumerator() {
			return GetEnumerator();
		}
		protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
			if(CollectionChanged != null) {
				CollectionChanged(this, e);
			}
		}
		public bool IsReadOnly { get { return false; } }
		public int Count {
			get {
				return fullCollection.Count - filteredCollection.Count;
			}
		}
		int FilteredItemsBeforeIndex(int index) {
			int count = 0;
			foreach(TItem item in filteredCollection.Keys) {
				if(fullCollection.IndexOf(item) < index) ++count;
			}
			return count;
		}
		int IList.Add(object value) {
			throw new Exception("Not supported");
		}
		void IList.Clear() {
			Clear();
		}
		bool IList.Contains(object value) {
			throw new Exception("Not supported");
		}
		int IList.IndexOf(object value) {
			for(int i = 0; i < fullCollection.Count; ++i) {
				if(fullCollection[i].Equals(value))
					return i - FilteredItemsBeforeIndex(i);
			}
			return -1;
		}
		void IList.Insert(int index, object value) {
			throw new Exception("Not supported");
		}
		bool IList.IsFixedSize {
			get { throw new Exception("Not supported"); }
		}
		bool IList.IsReadOnly {
			get { return IsReadOnly; }
		}
		void IList.Remove(object value) {
			throw new Exception("Not supported");
		}
		void IList.RemoveAt(int index) {
			throw new Exception("Not supported");
		}
		object IList.this[int index] {
			get {
				throw new Exception("Not supported");
			}
			set {
				throw new Exception("Not supported");
			}
		}
		void ICollection.CopyTo(Array array, int index) {
			throw new Exception("Not supported");
		}
		int ICollection.Count {
			get { return Count; }
		}
		bool ICollection.IsSynchronized {
			get { throw new Exception("Not supported"); }
		}
		object ICollection.SyncRoot {
			get { throw new Exception("Not supported"); }
		}
		public int IndexOf(TItem item) {
			throw new Exception("Not supported");
		}
		public void Insert(int index, TItem item) {
			throw new Exception("Not supported");
		}
		void IList<TItem>.RemoveAt(int index) {
			throw new Exception("Not supported");
		}
		TItem IList<TItem>.this[int index] {
			get {
				throw new Exception("Not supported");
			}
			set {
				throw new Exception("Not supported");
			}
		}
	}
}
